package com.kevin.utilits.elasticsearch;

import java.io.IOException;
import java.lang.reflect.Field;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ExecutionException;

import net.sf.json.JSONObject;

import org.elasticsearch.action.admin.indices.create.CreateIndexRequestBuilder;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexRequestBuilder;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.client.Client;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.query.MatchQueryBuilder.Operator;
import org.elasticsearch.index.query.MultiMatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.util.StringUtils;

import com.fasterxml.jackson.databind.JsonMappingException;
import com.google.gson.JsonParseException;

public class ElasticSearchUtil {

	private static Client client;

	private static String index = "sce-live";// 索引
	private static String type = "doraemon";// 类型
	
	static{
		try {
			init();
		} catch (UnknownHostException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 初始化客户端
	 */
	public static Client init() throws UnknownHostException{
		Map<String, String> map = System.getenv();
		String host = map.get("es_host");
		if(StringUtils.isEmpty(host)){
			host = "10.199.195.183";
		}
		String port = map.get("es_port");
		if(StringUtils.isEmpty(port)){
			port = "10800";
		}
		if(client == null){
			Settings settings = Settings.settingsBuilder().put("client.transport.ignore_cluster_name", true).build();
			client = TransportClient.builder().settings(settings).build().addTransportAddress(
					new InetSocketTransportAddress(InetAddress.getByName(host), Integer.parseInt(port)));
		}
		return client;
	}
	
	/**
	 * 关闭客户端
	 */
	public static void close(){
		if (client != null) {
			client.close();
		}
	}


	public static boolean createIndex() throws IOException {
		JSONObject indexJson = new JSONObject();
		indexJson.put("number_of_shards", "1");
		indexJson.put("number_of_replicas", "0");
		JSONObject settings = new JSONObject();
		settings.put("index", indexJson);

		JSONObject properties = new JSONObject();

		JSONObject userDef1 = new JSONObject();
		userDef1.put("type", "string");
		// userDef1.put("index", "analyzed");
		properties.put("userDef1", userDef1);

		JSONObject titile = new JSONObject();
		titile.put("type", "string");
		properties.put("titile", titile);

		JSONObject description = new JSONObject();
		description.put("type", "string");
		properties.put("description", description);

		JSONObject reason = new JSONObject();
		reason.put("type", "string");
		// reason.put("index", "analyzed");
		properties.put("reason", reason);

		JSONObject solution = new JSONObject();
		solution.put("type", "string");
		// solution.put("index", "analyzed");
		properties.put("solution", solution);

		JSONObject deptId = new JSONObject();
		deptId.put("type", "string");
		// deptId.put("index", "analyzed");
		properties.put("deptId", deptId);

		JSONObject typeJson = new JSONObject();
		typeJson.put("type", "string");
		// typeJson.put("index", "analyzed");
		properties.put("type", typeJson);

		JSONObject doraemon = new JSONObject();
		doraemon.put("properties", properties);
		JSONObject mappings = new JSONObject();
		mappings.put("doraemon", doraemon);

		JSONObject all = new JSONObject();
		all.put("settings", settings);
		all.put("mappings", mappings);

		init();
		CreateIndexRequestBuilder cirb = client.admin().indices().prepareCreate(index).setSource(all);
		CreateIndexResponse response = cirb.execute().actionGet();
		return response.isAcknowledged();
	}
	
	/**
	 * 创建索引
	 * @return
	 * @throws IOException
	 */
	public static boolean createIndex2() throws IOException{

		try{
			XContentBuilder mapping = XContentFactory.jsonBuilder()
				    .startObject()
				        .startObject("settings")
				          .field("number_of_shards", 1)//设置分片数量
				          .field("number_of_replicas", 0)//设置副本数量
				        .endObject()
				    .endObject()
				    .startObject()
				        .startObject(type)//type名称
				            .startObject("properties") //下面是设置文档列属性。
				               .startObject("type").field("type", "string").field("store", "yes").endObject()
				               .startObject("eventCount").field("type", "long").field("store", "yes").endObject()
				               .startObject("eventDate").field("type", "date").field("format", "dateOptionalTime").field("store", "yes").endObject()
				               .startObject("message").field("type", "string").field("index", "not_analyzed").field("store", "yes").endObject()
				            .endObject()
				        .endObject()
				    .endObject();
			
			init();
			CreateIndexRequestBuilder cirb = client.admin().indices().prepareCreate(index).setSource(mapping);
			 
			CreateIndexResponse response = cirb.execute().actionGet();
			return response.isAcknowledged();
		}finally{
			close();
		}
	}
	
	/**
	 * 创建文档
	 * @param client
	 * @param id
	 * @param transport
	 * @return
	 * @throws IOException
	 * @throws IllegalAccessException 
	 * @throws IllegalArgumentException 
	 * @throws SecurityException 
	 * @throws NoSuchFieldException 
	 */
	public static boolean createDoc(Client client, String id, Map<String, Object> object) throws IOException, IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
		if (null == object) {
			return false;
		}
		XContentBuilder mapping = XContentFactory.jsonBuilder().startObject();
		for (Entry<String, Object> entry : object.entrySet()) {
			String name = entry.getKey();
			Object value = entry.getValue();
			mapping.field(name, value);
		}
		mapping.endObject();
		IndexRequestBuilder indexRequestBuilder = client.prepareIndex(index, type, id).setSource(mapping);
		IndexResponse response = indexRequestBuilder.get();
		return response.isCreated();
	}
	
	
	/**
	 * 创建文档
	 * @param id
	 * @param bean
	 * @param fieldNames
	 * @return
	 * @throws IOException
	 * @throws IllegalAccessException 
	 * @throws IllegalArgumentException 
	 * @throws SecurityException 
	 * @throws NoSuchFieldException 
	 */
	public static boolean createDoc(String id, Object bean, String[] fieldNames) throws IOException, IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException{
		try {
			XContentBuilder mapping = XContentFactory.jsonBuilder().startObject();
			if(bean != null){
				Class<?> class1 = bean.getClass();
				if(fieldNames != null && fieldNames.length > 0){
					for(String name : fieldNames){
						Field field = class1.getDeclaredField(name);
						field.setAccessible(true);
						Object value = field.get(bean);
						mapping.field(name, value);
					}
				}
			}
			mapping.endObject();
			
			init();
			IndexRequestBuilder indexRequestBuilder = client.prepareIndex(index, type, id).setSource(mapping);
			IndexResponse response = indexRequestBuilder.get();
			return response.isCreated();
		} finally {
			close();
		}
	}
	
	/**
	 * 更新文档
	 * @param id
	 * @param bean
	 * @param fieldNames
	 * @throws IOException
	 * @throws InterruptedException
	 * @throws ExecutionException
	 * @throws IllegalAccessException 
	 * @throws IllegalArgumentException 
	 * @throws SecurityException 
	 * @throws NoSuchFieldException 
	 */
	public static void updateDoc(String id, Object bean, String[] fieldNames) throws IOException, InterruptedException, ExecutionException, IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
		try{
			XContentBuilder mapping = XContentFactory.jsonBuilder().startObject();
			if(bean != null){
				Class<?> class1 = bean.getClass();
				if(fieldNames != null && fieldNames.length > 0){
					for(String name : fieldNames){
						Field field = class1.getDeclaredField(name);
						field.setAccessible(true);
						Object value = field.get(bean);
						mapping.field(name, value);
					}
				}
			}
	        mapping.endObject();
			
			UpdateRequest updateRequest = new UpdateRequest(index, type, id);
			updateRequest.doc(mapping);
			
			init();
			client.update(updateRequest).get();
		} finally {
			close();
		}
	}

	/**
	 * 文档不存在则插入，存在则修改
	 * @param id
	 * @param bean
	 * @param fieldNames
	 * @return
	 * @throws IOException
	 * @throws InterruptedException
	 * @throws ExecutionException
	 * @throws IllegalAccessException 
	 * @throws IllegalArgumentException 
	 * @throws SecurityException 
	 * @throws NoSuchFieldException 
	 */
	public static void createOrUpdateDoc(String id, Object bean, String[] fieldNames) throws IOException, InterruptedException, ExecutionException, IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException{
			XContentBuilder mapping = XContentFactory.jsonBuilder().startObject();
			if (null == bean) {
				return;
			}
			if (fieldNames == null || fieldNames.length == 0) {
				return;
			}
			Class<?> class1 = bean.getClass();
			for (String name : fieldNames) {
				Field field = class1.getDeclaredField(name);
				field.setAccessible(true);
				mapping.field(name, field.get(bean));
			}
	        mapping.endObject();
			IndexRequest indexRequest = new IndexRequest(index, type, id).source(mapping);
			UpdateRequest updateRequest = new UpdateRequest(index, type, id).doc(mapping).upsert(indexRequest);
			init();
			client.update(updateRequest).get();
	}
	
    /**
     * 分页查询
     * 
     * @param start 数据起始下标
     * @param pageSize 每页条数
     * @param conditionMap 查询条件（完全匹配）
     * @param sortMap 排序字段
     * @return
     * @throws JsonParseException
     * @throws JsonMappingException
     * @throws IOException
     */
	public static Map<String, Object> search(int start, int pageSize, String keyword, List<String> condition,
			Map<String, Float> bootsMap, Map<String, SortOrder> sortMap) throws JsonParseException,
			JsonMappingException, IOException {
		if (condition != null && condition.size() == 0) {
			return null;
		}

		Map<String, Object> map = new HashMap<String, Object>();
		List<String> list = new ArrayList<>();
    		
		SearchRequestBuilder search = client.prepareSearch(index).setTypes(type).setSearchType(SearchType.DFS_QUERY_THEN_FETCH);
		MultiMatchQueryBuilder multiMatchQuery = QueryBuilders.multiMatchQuery(keyword, condition.toArray(new String[] {}));
		
		multiMatchQuery.operator(Operator.OR);
		// multiMatchQuery.

		for (Entry<String, Float> entry : bootsMap.entrySet()) {
			multiMatchQuery.field(entry.getKey(), entry.getValue());
		}
//	        searchRequestBuilder.setPostFilter(QueryBuilders.rangeQuery("id").from("1").to("5"));
        if(sortMap != null && sortMap.size() > 0){
        	for(Entry<String, SortOrder> entry : sortMap.entrySet()){
        		String fieldName = entry.getKey();
        		SortOrder sortOrder = entry.getValue();
				search.addSort(fieldName, sortOrder);
        	}
        }

		search.setFrom(start).setSize(pageSize);

		SearchResponse response = search.setQuery(multiMatchQuery).setExplain(true).execute().actionGet();
        SearchHits hits = response.getHits();
        map.put("total", hits.getTotalHits());
        
        SearchHit[] searchHits = hits.getHits();
        for (SearchHit searchHit : searchHits) {
        	String json = searchHit.getSourceAsString();
			list.add(json);
        }
        map.put("record", list);
        return map;
    }

    
	public static void main(String[] args) {
		try {

			createIndex();
			createDemo();

			searchDemo();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static void searchDemo() throws JsonMappingException, IOException {
		Map<String, Float> bootsMap = new HashMap<String, Float>();
		bootsMap.put("troubleTitle", 10000f);
		bootsMap.put("reportReason", 10000f);
		bootsMap.put("userDef1", 10000f);
		List<String> condition = new ArrayList<String>();
		condition.add("troubleTitle");
		condition.add("reportReason");
		condition.add("userDef1");
		search(200, 5, "档期已下线", condition, bootsMap, null);
	}

	public static void createDemo() throws IOException, InterruptedException, ExecutionException,
			IllegalAccessException, NoSuchFieldException {
		for (int i = 200; i < 300; i++) {
			TroubleEntity trouble = new TroubleEntity();
			trouble.setTroubleId(i);
			trouble.setTroubleTitle("档期已下线，PO：6000166931新增库存无法流入VIS 订单");
			trouble.setDescription("档期已下线，PO：6000166931，新增库存后，新增数据无法流入VIS系统，更新的库存无法绑定到新档期ID：1008702，此档期为预热档期，12.23 10:00开售，需紧急处理");
			trouble.setReportReason("已上报给监控中心处理，事件单号：E1612221812456。");
			trouble.setUserDef1("已上报给监控中心处理，事件单号：E1612221812456。");
			createOrUpdateDoc("t_" + trouble.getTroubleId(), trouble, new String[] { "troubleId", "troubleTitle",
					"reportReason", "userDef1" });
		}

	}
}
